package com.itheima.d4_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class ProxyUtil {
    public static Star createProxy(BigStar bigStar){
       /*
        Star starProxy = ProxyUtil.createProxy(s);

        starProxy.sing("好日子") starProxy.dance()，并且要java.lang.reflect.Proxy;反射包下面的Proxy类
        然后调用Proxy类的静态方法：public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
        newProxyInstance(ClassLoader loader,
                Class<?>[] interfaces,
                InvocationHandler h)
                参数1：用于指定一个类加载器，到时候用这个类加载器去加载生成的代理类
                参数2：指定生成的代理长什么样子，也就是指明代理有哪些方法
                参数3：用来指定生成的代理对象要干什么事情
                */
        /*
        返回的代理对象是object类型，所以要强转一下
参数一：ProxyUtil.class.getClassLoader():开发里都是用当前类ProxyUtil.class得到它的class对象，然后调用getClassLoader方法就可以得到当前类的类加载器了
参数二：new Class[]{Star.class}:代理有哪些方法会通过一个接口来告诉，但是Java怕你用多个接口来告诉代理有几个方法，所以Java用一个接口数组来接收
       现在是只有一个接口，那包装成一个数组给过去就好了
参数三：用InvocationHandler的对象来指定生成的代理对象要做什么，InvocationHandler是一个接口，接口不能直接创建对象，所以new一个匿名内部类
       对象来指定代理对象要做什么。然后重写匿名内部类中的invoke方法，因为代理对象实际要做什么是在invoke方法里面写的。
       同时这个方法比较难，有三个参数，也是一个所谓的回调方法：
       Object proxy参数：代理对象调用方法的时候实际上会回调invoke里面的方法，Java会把当前的代理对象当成一个object传给invoke方法，
                        也就是说我们程序员可以在invoke方法里面通过proxy参数可以拿到当前调用的这个代理对象
       Method method参数：会把当前调用的方法当做一个method传进来。
       Object[] args参数：会把方法的参数通过一个object数组传进来
        */
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class},
                new InvocationHandler() {
                    @Override // 回调方法
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 代理对象要做的事情，会在这里写代码
                        //获取当前调用的方法的名字，然后判断是否是“sing“方法，
                        if(method.getName().equals("sing")){
                            System.out.println("准备话筒，收钱20万");
                            //然后可以通过method调用invoke方法，再把原对象以及唱那首歌对应的参数传进来
                            return method.invoke(bigStar,args);
                        }else if(method.getName().equals("dance")){
                            System.out.println("准备场地，收钱1000万");
                            return method.invoke(bigStar,args);
                        }else {
                            return method.invoke(bigStar,args);
                        }
                    }
                });
        return starProxy;
    }
}
